#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_peripheral.h"
#include "console/console.h"
#include "esp_console.h"
#include "esp_mac.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include "services/gap/ble_svc_gap.h"

static const char *tag = "ble_adv";

#define SCAN_DURATION_MS 5000 // 扫描持续时间5秒
static const char *target_name = "elegrp-smart";
static int scan_restart_count = 0;

static uint8_t own_addr_type = BLE_OWN_ADDR_PUBLIC;
uint8_t base_mac[6];

void ble_store_config_init(void);
static void start_scan(void);

static void bleprph_on_reset(int reason)
{
	ESP_LOGE(tag, "Resetting state; reason=%d\n", reason);
}

static void bleprph_on_sync(void)
{
}

void bleprph_host_task(void *param)
{
	ESP_LOGI(tag, "BLE Host Task Started");
	/* This function will return only when nimble_port_stop() is executed */
	nimble_port_run();

	nimble_port_freertos_deinit();
}
/* 扫描回调函数实现 */
static int scan_callback(struct ble_gap_event *event, void *arg)
{
	struct ble_hs_adv_fields fields;
	int rc;

	switch (event->type) {
		case BLE_GAP_EVENT_DISC:
			/* 解析广播数据 */
			rc = ble_hs_adv_parse_fields(
				&fields, event->disc.data, event->disc.length_data);
			if (rc != 0) {
				return 0;
			}

			/* 名称匹配检测 */
			if (fields.name != NULL) {
				/* 构造临时字符串进行比较 */
				char name[fields.name_len + 1];
				memcpy(name, fields.name, fields.name_len);
				name[fields.name_len] = '\0';

				if (strcmp(name, target_name) == 0) {
					ESP_LOGI(tag, ">>> Target device found! <<<");

					/* 获取设备地址 */
					uint8_t addr[6];
					memcpy(addr, event->disc.addr.val, 6);
					addr[0] -= 2; // esp32的蓝牙mac地址比base mac大2

					/* 打印地址 */
					ESP_LOGI(tag, "mac: ");
					print_addr(addr);

					/* 停止扫描 */
					ble_gap_disc_cancel();
				}
			}
			break;

		case BLE_GAP_EVENT_DISC_COMPLETE:
			ESP_LOGI(tag, "Scan completed, restart times: %d", ++scan_restart_count);
			/* 重新启动扫描 */
			start_scan();
			break;

		default:
			break;
	}
	return 0;
}
static void start_scan(void)
{
	struct ble_gap_disc_params scan_params = {0};
	int rc;

	/* 配置扫描参数 */
	scan_params.passive = 0;					  // 主动扫描
	scan_params.itvl = BLE_GAP_ADV_ITVL_MS(100);  // 100ms间隔
	scan_params.window = BLE_GAP_ADV_ITVL_MS(50); // 50ms窗口
	scan_params.filter_duplicates = 1;			  // 过滤重复设备

	rc = ble_gap_disc(
		own_addr_type, SCAN_DURATION_MS, &scan_params, scan_callback, NULL);
	if (rc != 0) {
		ESP_LOGE(tag, "scan start failed: %d", rc);
	} else {
		ESP_LOGI(tag, "scan start...");
	}
}
static int hello_cmd(int argc, char **argv)
{
	printf("Hello from ESP32!\n");
	return 0;
}
static int get_mac_cmd(int argc, char **argv)
{
	start_scan();
	return 0;
}
void app_main(void)
{
	int rc;

	/* Initialize NVS — it is used to store PHY calibration data */
	esp_err_t ret = nvs_flash_init();
	if (ret == ESP_ERR_NVS_NO_FREE_PAGES
		|| ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
		ESP_ERROR_CHECK(nvs_flash_erase());
		ret = nvs_flash_init();
	}
	ESP_ERROR_CHECK(ret);

	ret = esp_base_mac_addr_get(base_mac);
	if (ret == ESP_OK) {
		ESP_LOGI(tag, "get base mac success");
		print_addr(base_mac);
	} else {
		ESP_LOGE(tag, "get base mac failed %d", ret);
	}

	ret = nimble_port_init();
	if (ret != ESP_OK) {
		ESP_LOGE(tag, "Failed to init nimble %d ", ret);
		return;
	}
	/* Initialize the NimBLE host configuration. */
	ble_hs_cfg.reset_cb = bleprph_on_reset;
	ble_hs_cfg.sync_cb = bleprph_on_sync;
	ble_hs_cfg.gatts_register_cb = NULL;
	ble_hs_cfg.store_status_cb = ble_store_util_status_rr;

	ble_hs_cfg.sm_io_cap = CONFIG_EXAMPLE_IO_TYPE;
	ble_hs_cfg.sm_sc = 0;

	/* Set the default device name. */
	rc = ble_svc_gap_device_name_set("elegrp-scan");
	assert(rc == 0);

	/* XXX Need to have template for store */
	ble_store_config_init();

	nimble_port_freertos_init(bleprph_host_task);

	esp_console_repl_t *repl = NULL;
	esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
	/* Prompt to be printed before each line.
	 * This can be customized, made dynamic, etc.
	 */
	repl_config.prompt = "BleScan"
						 ">";
	repl_config.max_cmdline_length = 1024;

	esp_console_cmd_t hello_cmd_desc = {.command = "hello",
										.help = "print hello",
										.hint = NULL,
										.func = &hello_cmd,
										.argtable = NULL};
	ESP_ERROR_CHECK(esp_console_cmd_register(&hello_cmd_desc));

	esp_console_cmd_t get_mac_cmd_desc = {.command = "getmac",
										  .help = "get device base mac which \
												device name is 'elegrp-smart'",
										  .hint = NULL,
										  .func = &get_mac_cmd,
										  .argtable = NULL};
	ESP_ERROR_CHECK(esp_console_cmd_register(&get_mac_cmd_desc));

	esp_console_dev_uart_config_t hw_config =
		ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
	ESP_ERROR_CHECK(esp_console_new_repl_uart(&hw_config, &repl_config, &repl));

	ESP_ERROR_CHECK(esp_console_start_repl(repl));
}
